#include "CRewardBackMgr.h"
#include "commerrno.h"
#include "../mainctrl.h"
#include "../act/CActCfg.h"
#include "../cmd/dataprepare.h"
#include "../item/CDropItem.h"
#include "../data/CPlayerOnlineData.h"
#include "../cmdinner/CCmdInnerActTitle.h"
#include "MsgAct.pb.h"
#include "MsgGM.pb.h"

void CRewardBackMgr::UpdateOpenZeroTime(CPlayerBaseInfo& stPlayerBase,
        CPlayerDetailInfoEx1& stPlayerDetailEx1, int iUpdateStat)
{
    if (stPlayerBase._shLevel < ENM_REWARD_BACK_OPEN_LEVEL)
    {
        return;
    }

    if (stPlayerDetailEx1._stRewardBack._iOpenZeroTime > 0)
    {
        return;
    }

    if (ENM_REWARD_BACK_STAT_LOGIN == iUpdateStat) //应该取本系统开启的最小的时间
    {
        CRewardBackZoneData& stZone =
            CMainCtrl::m_pstMain->m_stZoneOnlineData._stZoneData._stRewardBack;
        if (stZone._astList.Size() > 0)
        {
            stPlayerDetailEx1._stRewardBack._iOpenZeroTime =
                stZone._astList[stZone._astList.Size() - 1]._iDayZeroTime;
        }
        else
        {
            stPlayerDetailEx1._stRewardBack._iOpenZeroTime =
                CMainCtrl::m_pstMain->m_iDayZeroTime;
        }
    }
    else if (ENM_REWARD_BACK_STAT_LEVEL == iUpdateStat) //升级到达取当前时刻
    {
        stPlayerDetailEx1._stRewardBack._iOpenZeroTime =
            CMainCtrl::m_pstMain->m_iNow;
    }

    //这里修改了数据但都没有回存DB由调用方回存
}

void CRewardBackMgr::UpdateDetailToDB(CPlayerDetailInfo& stPlayerDetail)
{
    CVarObjectKey stKey;
    stKey.m_chDataType = DT_PLAYER_DETAIL_INFO;
    stKey.m_u64ID = stPlayerDetail._uiGID;
    CMainCtrl::m_pstMain->UpdateData(stKey, stPlayerDetail, VOP_UPDATE);
}

void CRewardBackMgr::UpdateDetailEx1ToDB(
        CPlayerDetailInfoEx1& stPlayerDetailEx1)
{
    CVarObjectKey stKey;
    stKey.m_chDataType = DT_PLAYER_DETAIL_EX1_INFO;
    stKey.m_u64ID = stPlayerDetailEx1._uiGID;
    CMainCtrl::m_pstMain->UpdateData(stKey, stPlayerDetailEx1, VOP_UPDATE);
}

void CRewardBackMgr::UpdateZoneDataToDB()
{
    CVarObjectKey stKey;
    stKey.m_chDataType = DT_ZONE_DATA;
    stKey.m_u64ID =
        CMainCtrl::m_pstMain->m_stZoneOnlineData._stZoneData._uiZoneID;
    CMainCtrl::m_pstMain->UpdateData(stKey,
        CMainCtrl::m_pstMain->m_stZoneOnlineData._stZoneData, VOP_UPDATE);
}

bool CRewardBackMgr::IsTargetAct(int iActID)
{
    if (ACT_ID_WORLD_BOSS == iActID ||
        ACT_ID_GRAN_BOSS == iActID ||
        ACT_ID_SLEN_BOSS == iActID ||
        ACT_ID_RAVAN_BOSS == iActID ||
        ACT_ID_HUFF_BOSS == iActID ||
        ACT_ID_ENEMY_ATK_CITY == iActID)
    {
        return true;
    }

    return false;
}

void CRewardBackMgr::SetActOpen(int iActID, int iWorldLevel)
{
    if (!IsTargetAct(iActID) || iWorldLevel <= 0)
    {
        CT_ERROR(("Act(%d) Can Not Reward Back Or World Level(%d) Error!",
            iActID, iWorldLevel));
        return;
    }

    int iActEndTime = CMainCtrl::m_pstMain->m_stActMgr.GetEndTime(iActID);
    if (iActEndTime <= 0)
    {
        CT_ERROR(("Get Act(%d) End Time(%d) Error!", iActID, iActEndTime));
        return;
    }

    int iIndex = 0;
    bool bUpdateDB = false;

    CRewardBackZoneData& stRewardBackZone =
        CMainCtrl::m_pstMain->m_stZoneOnlineData._stZoneData._stRewardBack;
    iIndex = stRewardBackZone.FindUnit(
        CMainCtrl::m_pstMain->m_iDayZeroTime);
    if (iIndex >= 0)
    {
        SetActOpen(stRewardBackZone.GetUnit(iIndex), iActID, iActEndTime,
            iWorldLevel, bUpdateDB);
    }
    else
    {
        CRewardBackUnit stUnit;
        stUnit._iDayZeroTime = CMainCtrl::m_pstMain->m_iDayZeroTime;

        SetActOpen(stUnit, iActID, iActEndTime, iWorldLevel, bUpdateDB);
        stRewardBackZone._astList.Update(stUnit);
    }

    if (bUpdateDB)
    {
        UpdateZoneDataToDB();
    }
}

void CRewardBackMgr::SetActOpen(CRewardBackUnit& stUnit, int iActID,
        int iActEndTime, int iWorldLevel, bool& bUpdateDB)
{
    bUpdateDB = false;

    if (ACT_ID_ENEMY_ATK_CITY == iActID)
    {
        if (stUnit._iEnemyCityTime != iActEndTime && stUnit._iEnemyCityLvl <= 0)
        {
            stUnit._iEnemyCityLvl = iWorldLevel;
            stUnit._iEnemyCityTime = iActEndTime;
            bUpdateDB = true;
        }
    }
    else if (ACT_ID_GRAN_BOSS == iActID ||
             ACT_ID_SLEN_BOSS == iActID ||
             ACT_ID_RAVAN_BOSS == iActID ||
             ACT_ID_HUFF_BOSS == iActID)
    {
        if (stUnit._iAcademyBossTime != iActEndTime &&
            stUnit._iAcademyBossLvl <= 0)
        {
            stUnit._iAcademyBossLvl = iWorldLevel;
            stUnit._iAcademyBossTime = iActEndTime;
            bUpdateDB = true;
        }
    }
    else if (ACT_ID_WORLD_BOSS == iActID)
    {
        if (stUnit._iWorldBossTimeOne <= 0 && stUnit._iWorldBossLvlOne <= 0)
        {
            stUnit._iWorldBossLvlOne = iWorldLevel;
            stUnit._iWorldBossTimeOne = iActEndTime;
            bUpdateDB = true;
        }
        else if (stUnit._iWorldBossTimeOne != iActEndTime &&
                 stUnit._iWorldBossLvlTwo <= 0)
        {
            stUnit._iWorldBossLvlTwo = iWorldLevel;
            stUnit._iWorldBossTimeTwo = iActEndTime;
            bUpdateDB = true;
        }
    }
}

void CRewardBackMgr::SetPlayerAct(unsigned int uiGID, int iActID)
{
    if (!IsTargetAct(iActID))
    {
        return;
    }

    CCmdInnerActTitle* pstCmd =
        (CCmdInnerActTitle*)CT_CMDFACTORY->CreateCmd(ID_MAIN_INNER_ACT_TITLE);
    if (!pstCmd){CT_ERROR(("create CCmdInnerActTitle error %u",uiGID));return;}

    pstCmd->pstMainCtrl = CMainCtrl::m_pstMain;
    pstCmd->_uiGID = uiGID;
    pstCmd->_iSubCmd = CActMgr::CMD_ACT_OPT_SUB_REWARD_BACK_SET_ACT;
    pstCmd->_iActID = iActID;
    pstCmd->Do(NULL);
}

void CRewardBackMgr::SetPlayerAct(CPlayerDetailInfoEx1& stPlayerDetailEx1,
        int iActID)
{
    if (!IsTargetAct(iActID))
    {
        return;
    }

    bool bUpdateDB = false;
    int iIndex = stPlayerDetailEx1._stRewardBack.FindUnit(
            CMainCtrl::m_pstMain->m_iDayZeroTime);
    if (iIndex >= 0)
    {
        SetPlayerAct(stPlayerDetailEx1._stRewardBack.GetUnit(iIndex), iActID,
            bUpdateDB);
    }
    else
    {
        CPlayerRewardBackUnit stUnit;
        stUnit._iDayZeroTime = CMainCtrl::m_pstMain->m_iDayZeroTime;

        SetPlayerAct(stUnit, iActID, bUpdateDB);
        stPlayerDetailEx1._stRewardBack._astList.Update(stUnit);
    }

    if (bUpdateDB)
    {
        UpdateDetailEx1ToDB(stPlayerDetailEx1);
    }
}

void CRewardBackMgr::SetPlayerAct(CPlayerRewardBackUnit& stUnit, int iActID,
        bool& bUpdateDB)
{
    bUpdateDB = false;
    int iIndex = 0;
    int iIntMask = 0;

    if (ACT_ID_ENEMY_ATK_CITY == iActID)
    {
        iIntMask = ENM_REWARD_BACK_BIT_ENEMY_ATK_CITY; //怪物攻城
        if (!(stUnit._iActMask & iIntMask)) //注意只能判断0或者非0
        {
            stUnit._iActMask |= iIntMask;
            bUpdateDB = true;
        }
    }
    else if (ACT_ID_GRAN_BOSS == iActID ||
             ACT_ID_SLEN_BOSS == iActID ||
             ACT_ID_RAVAN_BOSS == iActID ||
             ACT_ID_HUFF_BOSS == iActID)
    {
        iIntMask = ENM_REWARD_BACK_BIT_ACADEMY_BOSS; //学院BOSS
        if (!(stUnit._iActMask & iIntMask)) //注意只能判断0或者非0
        {
            stUnit._iActMask |= iIntMask;
            bUpdateDB = true;
        }
    }
    else if (ACT_ID_WORLD_BOSS == iActID)
    {
        CRewardBackZoneData& stRewardBackZone =
            CMainCtrl::m_pstMain->m_stZoneOnlineData._stZoneData._stRewardBack;
        iIndex = stRewardBackZone.FindUnit(
            CMainCtrl::m_pstMain->m_iDayZeroTime);
        if (iIndex < 0)
        {
            CT_ERROR(("Zone Data No Record On Zero Time(%d) When Deal Act(%d)",
                CMainCtrl::m_pstMain->m_iDayZeroTime, iActID));
            return;
        }

        CRewardBackUnit& stRewardBackUnit = stRewardBackZone.GetUnit(iIndex);
        if (stRewardBackUnit._iWorldBossLvlTwo > 0)
        {
            iIntMask = ENM_REWARD_BACK_BIT_WORLD_BOSS_TWO;  //世界BOSS第二场
            if (!(stUnit._iActMask & iIntMask)) //注意只能判断0或者非0
            {
                stUnit._iActMask |= iIntMask;
                bUpdateDB = true;
            }
        }
        else if (stRewardBackUnit._iWorldBossLvlOne > 0)
        {
            iIntMask = ENM_REWARD_BACK_BIT_WORLD_BOSS_ONE; //世界BOSS第一场
            if (!(stUnit._iActMask & iIntMask)) //注意只能判断0或者非0
            {
                stUnit._iActMask |= iIntMask;
                bUpdateDB = true;
            }
        }
    }
}

void CRewardBackMgr::GetUnActList(CPlayerBaseInfo& stPlayerBase,
        CPlayerDetailInfoEx1& stPlayerDetailEx1, int iActID,
        T_REWARD_BACK_LIST& stLevelList)
{
    stLevelList.Clear();
    if (!IsTargetAct(iActID))
    {
        return;
    }

    if (stPlayerDetailEx1._stRewardBack._iOpenZeroTime <= 0)
    {
        CT_ERROR(("Role(%u) Open Zero Time(%d) Error!",
            stPlayerDetailEx1._uiGID,
            stPlayerDetailEx1._stRewardBack._iOpenZeroTime));
        return;
    }

    int iIndex = 0;
    int iIntMask = 0;
    CRewardBackZoneData& stZone =
        CMainCtrl::m_pstMain->m_stZoneOnlineData._stZoneData._stRewardBack;
    for (int i = 0; i < stZone._astList.Size(); ++i)
    {
        if (stZone._astList[i]._iDayZeroTime <= 0) //出错啦
        {
            CT_ERROR(("Zone Zero Time Error!"));
            continue;
        }

        if (stZone._astList[i]._iDayZeroTime >=
                CMainCtrl::m_pstMain->m_iDayZeroTime)//当天不能找回
        {
            continue;
        }

        //七天之后的不能找回
        if (CMainCtrl::m_pstMain->m_iDayZeroTime >
                (stZone._astList[i]._iDayZeroTime + 7 * 86400))
        {
            continue;
        }

        if (ACT_ID_ENEMY_ATK_CITY == iActID &&
            stZone._astList[i]._iEnemyCityTime > 0)
        {
            if (stZone._astList[i]._iEnemyCityTime <=
                    stPlayerDetailEx1._stRewardBack._iOpenZeroTime)
            {
                continue;
            }

            iIndex = stPlayerDetailEx1._stRewardBack.FindUnit(
                stZone._astList[i]._iDayZeroTime);
            if (iIndex >= 0)
            {
                CPlayerRewardBackUnit& stUnit =
                    stPlayerDetailEx1._stRewardBack.GetUnit(iIndex);

                iIntMask = ENM_REWARD_BACK_BIT_ENEMY_ATK_CITY; //怪物攻城
                if ((stUnit._iActMask & iIntMask)) //注意只能判断0或者非0
                {
                    continue;
                }
            }

            //找不到 表示没有参加 可以找回;找到了但没有参加 可以找回
            if (stPlayerBase._shLevel < stZone._astList[i]._iEnemyCityLvl)
            {
                stLevelList.AddOneItem(stPlayerBase._shLevel);
            }
            else
            {
                stLevelList.AddOneItem(stZone._astList[i]._iEnemyCityLvl);
            }
        }
        else if ((ACT_ID_GRAN_BOSS == iActID ||
                  ACT_ID_SLEN_BOSS == iActID ||
                  ACT_ID_RAVAN_BOSS == iActID ||
                  ACT_ID_HUFF_BOSS == iActID) &&
                 stZone._astList[i]._iAcademyBossTime > 0)
        {
            if (stZone._astList[i]._iAcademyBossTime <=
                    stPlayerDetailEx1._stRewardBack._iOpenZeroTime)
            {
                continue;
            }

            iIndex = stPlayerDetailEx1._stRewardBack.FindUnit(
                stZone._astList[i]._iDayZeroTime);
            if (iIndex >= 0)
            {
                CPlayerRewardBackUnit& stUnit =
                    stPlayerDetailEx1._stRewardBack.GetUnit(iIndex);

                iIntMask = ENM_REWARD_BACK_BIT_ACADEMY_BOSS; //学院BOSS
                if ((stUnit._iActMask & iIntMask)) //注意只能判断0或者非0
                {
                    continue;
                }
            }

            //找不到 表示没有参加 可以找回;找到了但没有参加 可以找回
            if (stPlayerBase._shLevel < stZone._astList[i]._iAcademyBossLvl)
            {
                stLevelList.AddOneItem(stPlayerBase._shLevel);
            }
            else
            {
                stLevelList.AddOneItem(stZone._astList[i]._iAcademyBossLvl);
            }
        }
        else if (ACT_ID_WORLD_BOSS == iActID)
        {
            if (stZone._astList[i]._iWorldBossTimeOne >
                    stPlayerDetailEx1._stRewardBack._iOpenZeroTime)
            {
                iIndex = stPlayerDetailEx1._stRewardBack.FindUnit(
                    stZone._astList[i]._iDayZeroTime);
                if (iIndex >= 0)
                {
                    CPlayerRewardBackUnit& stUnit =
                        stPlayerDetailEx1._stRewardBack.GetUnit(iIndex);

                    iIntMask = ENM_REWARD_BACK_BIT_WORLD_BOSS_ONE; //世界BOSS第一场
                    if (!(stUnit._iActMask & iIntMask)) //注意只能判断0或者非0
                    {
                        //找到了但没有参加 可以找回
                        if (stPlayerBase._shLevel <
                                stZone._astList[i]._iWorldBossLvlOne)
                        {
                            stLevelList.AddOneItem(stPlayerBase._shLevel);
                        }
                        else
                        {
                            stLevelList.AddOneItem(
                                stZone._astList[i]._iWorldBossLvlOne);
                        }
                    }
                }
                else
                {
                    //找不到 表示没有参加 可以找回
                    if (stPlayerBase._shLevel <
                            stZone._astList[i]._iWorldBossLvlOne)
                    {
                        stLevelList.AddOneItem(stPlayerBase._shLevel);
                    }
                    else
                    {
                        stLevelList.AddOneItem(
                            stZone._astList[i]._iWorldBossLvlOne);
                    }
                }
            }

            if (stZone._astList[i]._iWorldBossTimeTwo >
                    stPlayerDetailEx1._stRewardBack._iOpenZeroTime)
            {
                iIndex = stPlayerDetailEx1._stRewardBack.FindUnit(
                    stZone._astList[i]._iDayZeroTime);
                if (iIndex >= 0)
                {
                    CPlayerRewardBackUnit& stUnit =
                        stPlayerDetailEx1._stRewardBack.GetUnit(iIndex);

                    iIntMask = ENM_REWARD_BACK_BIT_WORLD_BOSS_TWO; //世界BOSS第二场
                    if (!(stUnit._iActMask & iIntMask)) //注意只能判断0或者非0
                    {
                        //找到了但没有参加 可以找回
                        if (stPlayerBase._shLevel <
                                stZone._astList[i]._iWorldBossLvlTwo)
                        {
                            stLevelList.AddOneItem(stPlayerBase._shLevel);
                        }
                        else
                        {
                            stLevelList.AddOneItem(
                                stZone._astList[i]._iWorldBossLvlTwo);
                        }
                    }
                }
                else
                {
                    //找不到 表示没有参加 可以找回
                    if (stPlayerBase._shLevel <
                            stZone._astList[i]._iWorldBossLvlTwo)
                    {
                        stLevelList.AddOneItem(stPlayerBase._shLevel);
                    }
                    else
                    {
                        stLevelList.AddOneItem(
                            stZone._astList[i]._iWorldBossLvlTwo);
                    }
                }
            }
        }
    }
}

void CRewardBackMgr::GetRewardValue(int iActID, int& iExp, int& iRepu,
        int& iSilver, T_REWARD_BACK_LIST& stLevelList)
{
    iExp = 0;
    iRepu = 0;
    iSilver = 0;
    if (!IsTargetAct(iActID))
    {
        return;
    }

    int iIndex = 0;
    int iExpTmp = 0;
    int iRepuTmp = 0;
    int iSilverTmp = 0;
    int iRatioValue = 0;
    int64 i64RatioTmp = 0;

    for (int i = 0; i < stLevelList.Size(); ++i)
    {
        iExpTmp = 0;
        iRepuTmp = 0;
        iSilverTmp = 0;

        iIndex = CMainCtrl::m_pstMain->m_stWorldBossMgr.FindRewardConfig(
            stLevelList[i]);
        if (iIndex < 0)
        {
            CT_ERROR(("reward back world level(%d) cfg empty", stLevelList[i]));
            continue;
        }
        CWorldBossCfgReward& stRewardCfg =
            CMainCtrl::m_pstMain->m_stWorldBossMgr.GetRewardConfig(iIndex);
        
        if (ACT_ID_ENEMY_ATK_CITY == iActID)
        {
            iExpTmp = stRewardCfg._iEacExpBonus;
            iRepuTmp = 0;
            iSilverTmp = stRewardCfg._iEacSilverBonus;
            iRatioValue = stRewardCfg.GetRewardBackEnemyCity();
        }
        else if (ACT_ID_GRAN_BOSS == iActID ||
                 ACT_ID_SLEN_BOSS == iActID ||
                 ACT_ID_RAVAN_BOSS == iActID ||
                 ACT_ID_HUFF_BOSS == iActID)
        {
            iExpTmp = stRewardCfg.GetAcademyExp();
            iRepuTmp = stRewardCfg.GetAcademyReputation();
            iSilverTmp = stRewardCfg.GetAcademySilver();
            iRatioValue = stRewardCfg.GetRewardBackAcademyBoss();
        }
        else if (ACT_ID_WORLD_BOSS == iActID)
        {
            iExpTmp = stRewardCfg.GetExpRatio();
            iRepuTmp = stRewardCfg.GetReputationRatio();
            iSilverTmp = stRewardCfg.GetSilverRatio();
            iRatioValue = stRewardCfg.GetRewardBackWorldBoss();
        }

        i64RatioTmp = INT64_1 * iExpTmp * iRatioValue;
        i64RatioTmp /= BATTLE_RATE_SKILL_PERCENT;
        iExpTmp = (int)(i64RatioTmp);
        
        i64RatioTmp = INT64_1 * iRepuTmp * iRatioValue;
        i64RatioTmp /= BATTLE_RATE_SKILL_PERCENT;
        iRepuTmp = (int)(i64RatioTmp);
        
        i64RatioTmp = INT64_1 * iSilverTmp * iRatioValue;
        i64RatioTmp /= BATTLE_RATE_SKILL_PERCENT;
        iSilverTmp = (int)(i64RatioTmp);

        if (iExpTmp > 0) {iExp += iExpTmp;}
        if (iRepuTmp > 0) {iRepu += iRepuTmp;}
        if (iSilverTmp > 0) {iSilver += iSilverTmp;}
    }
}

int CRewardBackMgr::CalcExp(short& shLevel, int64& i64RoleExp, int64 i64AddExp,
        int64& i64LevelExp)
{
    unsigned int uiLevelExp = 0;

    int iRet = CMainCtrl::m_pstMain->m_stRoleConfigMgr.GetLevelUpExp(shLevel,
            uiLevelExp);
    CT_RETURN(iRet);

    i64LevelExp = (int64)(uiLevelExp);
    
    int64 i64Tmp = i64RoleExp + i64AddExp;

    while(i64Tmp >= i64LevelExp)
    {
        if (shLevel >= OPEN_ROLE_LEVEL)
        {
            break;//必须退出
        }
        else
        {
            i64Tmp -= i64LevelExp;
            ++shLevel;
        }

        iRet = CMainCtrl::m_pstMain->m_stRoleConfigMgr.GetLevelUpExp(shLevel,
            uiLevelExp);
        CT_RETURN(iRet);

        i64LevelExp = (int64)(uiLevelExp);
    }

    i64RoleExp = i64Tmp;
    if (shLevel >= OPEN_ROLE_LEVEL)
    {
        i64RoleExp = 0;
    }

    return 0;
}

int CRewardBackMgr::GetInfo(CPlayerBaseInfo& stPlayerBase,
        CPlayerDetailInfoEx1& stPlayerDetailEx1, MsgAnsRewardBack& stAns)
{
    if (stPlayerBase._shLevel < ENM_REWARD_BACK_OPEN_LEVEL)
    {
        return ERROR_SYS_NOT_OPEN;
    }

    MsgRewardBackInfo* pstMsgInfo = stAns.mutable_info();
    if (!pstMsgInfo)
    {
        CT_ERROR(("MsgRewardBackInfo Pointer Null!"));
        return RET_SYS_NULL_POINTER;
    }

    int iExp = 0;
    int iRepu = 0;
    int iSilver = 0;
    int iExpTotal = 0;
    int iRepuTotal = 0;
    int iSilverTotal = 0;
    T_REWARD_BACK_LIST stLevelList;

    GetUnActList(stPlayerBase, stPlayerDetailEx1, ACT_ID_WORLD_BOSS,
        stLevelList);
    GetRewardValue(ACT_ID_WORLD_BOSS, iExp, iRepu, iSilver, stLevelList);
    MsgRewardBackUnit* pstWorldBossUnit = pstMsgInfo->add_act_info();
    if (!pstWorldBossUnit)
    {
        CT_ERROR(("MsgRewardBackUnit Pointer Null!"));
        return RET_SYS_NULL_POINTER;
    }
    pstWorldBossUnit->set_act_id(ACT_ID_WORLD_BOSS);
    pstWorldBossUnit->set_times(stLevelList.Size());
    pstWorldBossUnit->set_exp(iExp);
    pstWorldBossUnit->set_silver(iSilver);
    pstWorldBossUnit->set_reputation(iRepu);
    if (iExp > 0){iExpTotal += iExp;}
    if (iRepu > 0){iRepuTotal += iRepu;}
    if (iSilver > 0){iSilverTotal += iSilver;}

    GetUnActList(stPlayerBase, stPlayerDetailEx1, ACT_ID_ENEMY_ATK_CITY,
        stLevelList);
    GetRewardValue(ACT_ID_ENEMY_ATK_CITY, iExp, iRepu, iSilver, stLevelList);
    MsgRewardBackUnit* pstEnemyCityUnit = pstMsgInfo->add_act_info();
    if (!pstEnemyCityUnit)
    {
        CT_ERROR(("MsgRewardBackUnit Pointer Null!"));
        return RET_SYS_NULL_POINTER;
    }
    pstEnemyCityUnit->set_act_id(ACT_ID_ENEMY_ATK_CITY);
    pstEnemyCityUnit->set_times(stLevelList.Size());
    pstEnemyCityUnit->set_exp(iExp);
    pstEnemyCityUnit->set_silver(iSilver);
    pstEnemyCityUnit->set_reputation(iRepu);
    if (iExp > 0){iExpTotal += iExp;}
    if (iRepu > 0){iRepuTotal += iRepu;}
    if (iSilver > 0){iSilverTotal += iSilver;}

    GetUnActList(stPlayerBase, stPlayerDetailEx1, ACT_ID_GRAN_BOSS,
        stLevelList);
    GetRewardValue(ACT_ID_GRAN_BOSS, iExp, iRepu, iSilver, stLevelList);
    MsgRewardBackUnit* pstAcademyBossUnit = pstMsgInfo->add_act_info();
    if (!pstAcademyBossUnit)
    {
        CT_ERROR(("MsgRewardBackUnit Pointer Null!"));
        return RET_SYS_NULL_POINTER;
    }
    pstAcademyBossUnit->set_act_id(ACT_ID_GRAN_BOSS);
    pstAcademyBossUnit->set_times(stLevelList.Size());
    pstAcademyBossUnit->set_exp(iExp);
    pstAcademyBossUnit->set_silver(iSilver);
    pstAcademyBossUnit->set_reputation(iRepu);
    if (iExp > 0){iExpTotal += iExp;}
    if (iRepu > 0){iRepuTotal += iRepu;}
    if (iSilver > 0){iSilverTotal += iSilver;}

    //必须使用临时变量
    int iFreeRatio = 0;
    int iGoldRatio = 0;
    short shFreeLevel = stPlayerBase._shLevel;
    short shGoldLevel = stPlayerBase._shLevel;
    int64 i64FreeRoleExp = stPlayerBase._i64NowExp;
    int64 i64GoldRoleExp = stPlayerBase._i64NowExp;
    int64 i64FreeLevelExp = 0;
    int64 i64GoldLevelExp = 0;
    CalcExp(shFreeLevel, i64FreeRoleExp, iExpTotal/2, i64FreeLevelExp);
    CalcExp(shGoldLevel, i64GoldRoleExp, iExpTotal, i64GoldLevelExp);

    pstMsgInfo->set_free_level(shFreeLevel);
    pstMsgInfo->set_gold_level(shGoldLevel);
    
    if (i64FreeLevelExp > 0)
    {
        //四舍五入的写法
        i64FreeRoleExp =
            INT64_1 * i64FreeRoleExp * BATTLE_RATE_SKILL_PERCENT * 10;
        i64FreeRoleExp /= i64FreeLevelExp;
        iFreeRatio = (int)i64FreeRoleExp + 5;
        iFreeRatio /= 10;
    }
    if (i64GoldLevelExp > 0)
    {
        //四舍五入的写法
        i64GoldRoleExp =
            INT64_1 * i64GoldRoleExp * BATTLE_RATE_SKILL_PERCENT * 10;
        i64GoldRoleExp /= i64GoldLevelExp;
        iGoldRatio = (int)i64GoldRoleExp + 5;
        iGoldRatio /= 10;
    }

    pstMsgInfo->set_free_ratio(iFreeRatio);
    pstMsgInfo->set_gold_ratio(iGoldRatio);

    return 0;
}

void CRewardBackMgr::SendReward(unsigned int uiGID, int iExp, int iRepu,
        int iSilver)
{
    CDropItem stDropItem;
    if (iExp > 0)
    {
        stDropItem.DropItem(ITEM_TYPE_EXP, iExp);
    }

    if (iRepu > 0)
    {
        stDropItem.DropItem(ITEM_TYPE_REPUTATION, iRepu);
    }

    if (iSilver > 0)
    {
        stDropItem.DropItem(ITEM_TYPE_SILVER, iSilver);
    }

    if (stDropItem.Size() > 0)
    {
        stDropItem.SetOssModule(OSS_MODULE_REWARD_BACK);
        CMainCtrl::m_pstMain->m_stItemMgr.DropItem(NULL, uiGID, stDropItem);
    }
}

int CRewardBackMgr::FreeBack(CPlayerBaseInfo& stPlayerBase,
        CPlayerDetailInfoEx1& stPlayerDetailEx1, MsgAnsRewardBack& stAns)
{
    if (stPlayerBase._shLevel < ENM_REWARD_BACK_OPEN_LEVEL)
    {
        return ERROR_SYS_NOT_OPEN;
    }

    int iTimesTotal = 0;
    int iExp = 0;
    int iRepu = 0;
    int iSilver = 0;
    int iExpTotal = 0;
    int iRepuTotal = 0;
    int iSilverTotal = 0;
    T_REWARD_BACK_LIST stLevelList;

    GetUnActList(stPlayerBase, stPlayerDetailEx1, ACT_ID_WORLD_BOSS,
        stLevelList);
    GetRewardValue(ACT_ID_WORLD_BOSS, iExp, iRepu, iSilver, stLevelList);
    iTimesTotal += stLevelList.Size();
    if (iExp > 0){iExpTotal += iExp;}
    if (iRepu > 0){iRepuTotal += iRepu;}
    if (iSilver > 0){iSilverTotal += iSilver;}

    GetUnActList(stPlayerBase, stPlayerDetailEx1, ACT_ID_ENEMY_ATK_CITY,
        stLevelList);
    GetRewardValue(ACT_ID_ENEMY_ATK_CITY, iExp, iRepu, iSilver, stLevelList);
    iTimesTotal += stLevelList.Size();
    if (iExp > 0){iExpTotal += iExp;}
    if (iRepu > 0){iRepuTotal += iRepu;}
    if (iSilver > 0){iSilverTotal += iSilver;}

    GetUnActList(stPlayerBase, stPlayerDetailEx1, ACT_ID_GRAN_BOSS,
        stLevelList);
    GetRewardValue(ACT_ID_GRAN_BOSS, iExp, iRepu, iSilver, stLevelList);
    iTimesTotal += stLevelList.Size();
    if (iExp > 0){iExpTotal += iExp;}
    if (iRepu > 0){iRepuTotal += iRepu;}
    if (iSilver > 0){iSilverTotal += iSilver;}

    if (iTimesTotal <= 0 ||
        (iExpTotal <= 0 && iRepuTotal <= 0 && iSilverTotal <= 0))
    {
        return ERROR_REWARD_BACK_NO_REWARD_BACK;
    }

    SendReward(stPlayerBase._uiGID, iExpTotal/2, iRepuTotal/2, iSilverTotal/2);

    stPlayerDetailEx1._stRewardBack._iOpenZeroTime =
        CMainCtrl::m_pstMain->m_iDayZeroTime;

    UpdateDetailEx1ToDB(stPlayerDetailEx1);

    return GetInfo(stPlayerBase, stPlayerDetailEx1, stAns);
}

int CRewardBackMgr::GoldBack(CPlayerBaseInfo& stPlayerBase,
        CPlayerDetailInfo& stPlayerDetail,
        CPlayerDetailInfoEx1& stPlayerDetailEx1,
        CPlayerOnlineData& stPlayerOnline, MsgAnsRewardBack& stAns)
{
    if (stPlayerBase._shLevel < ENM_REWARD_BACK_OPEN_LEVEL)
    {
        return ERROR_SYS_NOT_OPEN;
    }

    int iRet = 0;
    int iItemCount = 0;
    int iItemDelete = 0;
    int iCostGold = 0;
    int iTimesTotal = 0;
    int iNotifyMask = 0;
    int iExp = 0;
    int iRepu = 0;
    int iSilver = 0;
    int iExpTotal = 0;
    int iRepuTotal = 0;
    int iSilverTotal = 0;
    T_REWARD_BACK_LIST stLevelList;

    GetUnActList(stPlayerBase, stPlayerDetailEx1, ACT_ID_WORLD_BOSS,
        stLevelList);
    GetRewardValue(ACT_ID_WORLD_BOSS, iExp, iRepu, iSilver, stLevelList);
    iTimesTotal += stLevelList.Size();
    if (iExp > 0){iExpTotal += iExp;}
    if (iRepu > 0){iRepuTotal += iRepu;}
    if (iSilver > 0){iSilverTotal += iSilver;}

    GetUnActList(stPlayerBase, stPlayerDetailEx1, ACT_ID_ENEMY_ATK_CITY,
        stLevelList);
    GetRewardValue(ACT_ID_ENEMY_ATK_CITY, iExp, iRepu, iSilver, stLevelList);
    iTimesTotal += stLevelList.Size();
    if (iExp > 0){iExpTotal += iExp;}
    if (iRepu > 0){iRepuTotal += iRepu;}
    if (iSilver > 0){iSilverTotal += iSilver;}

    GetUnActList(stPlayerBase, stPlayerDetailEx1, ACT_ID_GRAN_BOSS,
        stLevelList);
    GetRewardValue(ACT_ID_GRAN_BOSS, iExp, iRepu, iSilver, stLevelList);
    iTimesTotal += stLevelList.Size();
    if (iExp > 0){iExpTotal += iExp;}
    if (iRepu > 0){iRepuTotal += iRepu;}
    if (iSilver > 0){iSilverTotal += iSilver;}

    if (iTimesTotal <= 0 ||
        (iExpTotal <= 0 && iRepuTotal <= 0 && iSilverTotal <= 0))
    {
        return ERROR_REWARD_BACK_NO_REWARD_BACK;
    }

    iItemCount = CMainCtrl::m_pstMain->m_stStorageMgr.GetItemCount(
        stPlayerOnline._stUserStorage, ITEM_TYPE_MATERIAL,
        ENM_REWARD_BACK_COST_ITEM_ID);
    if (iItemCount < 0)
    {
        CT_ERROR(("Role(%u) Reward Back Item Error(%d)", stPlayerBase._uiGID,
            iItemCount));
        iItemCount = 0;
    }

    if (iTimesTotal > iItemCount)
    {
        iItemDelete = iItemCount;
        iCostGold =
            (iTimesTotal - iItemCount) * ENM_REWARD_BACK_GOLD_EACH_TIMES;
    }
    else
    {
        iItemDelete = iTimesTotal;
    }

    if (iCostGold > 0)
    {
        iRet = CMainCtrl::m_pstMain->m_stItemMgr.SubGold(stPlayerBase,
            OSS_MONEY_MODULE_56, iCostGold);
        CHECK_RETURN(iRet);

        iNotifyMask |= NOTIFY_USER_MONEY;
    }

    if (iItemDelete > 0)
    {
        iRet = CMainCtrl::m_pstMain->m_stStorageMgr.TakeOutItem(
            stPlayerOnline._stUserStorage, ITEM_TYPE_MATERIAL,
            ENM_REWARD_BACK_COST_ITEM_ID, iItemDelete);
        if (iRet)
        {
            CT_ERROR(("Role(%u) Delete Num(%d) Reward Item(%d) Error(%d)",
                stPlayerBase._uiGID, iItemDelete, ENM_REWARD_BACK_COST_ITEM_ID,
                iRet));
        }

        iNotifyMask |= NOTIFY_BAG_INFO;
        iNotifyMask |= NOTIFY_WARE_INFO;

        //入库背包仓库
        CMainCtrl::m_pstMain->m_stStorageMgr.GetData(
            stPlayerOnline._stUserStorage, stPlayerDetail._stUserStorage);
        CVarObjectKey stKey;
        stKey.m_chDataType = DT_PLAYER_DETAIL_INFO;
        stKey.m_u64ID = stPlayerBase._uiGID;
        CMainCtrl::m_pstMain->UpdateData(stKey, stPlayerDetail, VOP_UPDATE);
    }

    if (iNotifyMask > 0)
    {
        CMainCtrl::m_pstMain->m_stNotifyMgr.Notify(stPlayerBase._uiGID,
            iNotifyMask);
    }

    SendReward(stPlayerBase._uiGID, iExpTotal, iRepuTotal, iSilverTotal);

    stPlayerDetailEx1._stRewardBack._iOpenZeroTime =
        CMainCtrl::m_pstMain->m_iDayZeroTime;

    UpdateDetailEx1ToDB(stPlayerDetailEx1);

    return GetInfo(stPlayerBase, stPlayerDetailEx1, stAns);
}

int CRewardBackMgr::GMDeal(CPlayerBaseInfo& stPlayerBase,
        CPlayerDetailInfoEx1& stPlayerDetailEx1, MsgReqGMPlayer& stReq,
        MsgAnsGMPlayer& stAns)
{
    if (stReq.datas_size() > 0)//重置逻辑
    {
        stPlayerDetailEx1._stRewardBack._iOpenZeroTime = 0;
        stPlayerDetailEx1._stRewardBack._astList.Clear();
        UpdateDetailEx1ToDB(stPlayerDetailEx1);
        return 0;//因为依赖_iOpenZeroTime以下信息不准需要重新登录
    }

    CTSizeString<MAX_BATTLE_NAME_BUFF> szNameStr;

    CRewardBackZoneData& stZone =
        CMainCtrl::m_pstMain->m_stZoneOnlineData._stZoneData._stRewardBack;

    szNameStr.Cat("Zone记录天数:%d", stZone._astList.Size());

    for (int i = 0; i < stZone._astList.Size(); ++i)
    {
        CRewardBackUnit& stUnit = stZone._astList[i];
        szNameStr.Cat("\n第%d元素:ZeroTime(%d)EnemyCity(%d %d)AcademyBoss" \
            "(%d %d)WorldBossOne(%d %d)WorldBossTwo(%d %d)", i,
            stUnit._iDayZeroTime, stUnit._iEnemyCityLvl, stUnit._iEnemyCityTime,
            stUnit._iAcademyBossLvl, stUnit._iAcademyBossTime,
            stUnit._iWorldBossLvlOne, stUnit._iWorldBossTimeOne,
            stUnit._iWorldBossLvlTwo, stUnit._iWorldBossTimeTwo);
    }

    szNameStr.Cat("\n玩家记录时刻:%d 参加天数:%d",
        stPlayerDetailEx1._stRewardBack._iOpenZeroTime,
        stPlayerDetailEx1._stRewardBack._astList.Size());
    for (int i = 0; i < stPlayerDetailEx1._stRewardBack._astList.Size(); ++i)
    {
        CPlayerRewardBackUnit& stUnit =
            stPlayerDetailEx1._stRewardBack._astList[i];
        szNameStr.Cat("\n第%d元素:ZeroTime(%d)ActMask(%d)", i,
            stUnit._iDayZeroTime, stUnit._iActMask);
    }

    MsgAnsRewardBack stRewardBackAns;
    GetInfo(stPlayerBase, stPlayerDetailEx1, stRewardBackAns);

    if (stRewardBackAns.has_info())
    {
        const MsgRewardBackInfo& stInfo = stRewardBackAns.info();
        
        szNameStr.Cat("\n普通找回(%d %d)符石找回(%d %d)活动个数(%d)",
            stInfo.free_level(), stInfo.free_ratio(), stInfo.gold_level(),
            stInfo.gold_ratio(), stInfo.act_info_size());

        for (int i = 0; i < stInfo.act_info_size(); ++i)
        {
            const MsgRewardBackUnit& stUnit = stInfo.act_info(i);
            szNameStr.Cat("\n活动(%d)未完成次数(%d)累计可找回(%d %d %d)",
                stUnit.act_id(), stUnit.times(), stUnit.exp(),
                stUnit.reputation(), stUnit.silver());
        }
    }

    stAns.set_name(szNameStr.Get());

    return 0;
}

template<>
bool CTRankArray<CPlayerRewardBackUnit, MAX_REWARD_BACK_DAY_COUNT>::IsSame(
        CPlayerRewardBackUnit& stA, CPlayerRewardBackUnit& stB) const
{
    return (stA.GetDayZeroTime() == stB.GetDayZeroTime());
}

template<>
int CTRankArray<CPlayerRewardBackUnit, MAX_REWARD_BACK_DAY_COUNT>::CmpFunc(
        CPlayerRewardBackUnit& stA, CPlayerRewardBackUnit& stB) const
{
    if (stA.GetDayZeroTime() > stB.GetDayZeroTime())
    {
        return 1;
    }
    else if (stA.GetDayZeroTime() < stB.GetDayZeroTime())
    {
        return -1;
    }

    return 0;
}

template<>
bool CTRankArray<CRewardBackUnit, MAX_REWARD_BACK_DAY_COUNT>::IsSame(
        CRewardBackUnit& stA, CRewardBackUnit& stB) const
{
    return (stA.GetDayZeroTime() == stB.GetDayZeroTime());
}

template<>
int CTRankArray<CRewardBackUnit, MAX_REWARD_BACK_DAY_COUNT>::CmpFunc(
        CRewardBackUnit& stA, CRewardBackUnit& stB) const
{
    if (stA.GetDayZeroTime() > stB.GetDayZeroTime())
    {
        return 1;
    }
    else if (stA.GetDayZeroTime() < stB.GetDayZeroTime())
    {
        return -1;
    }

    return 0;
}

